package com.ruoyi.product.service.impl;

import com.alibaba.fastjson.JSON;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.product.domain.ProductDoc;
import com.ruoyi.product.request.SearchRequestParams;
import com.ruoyi.product.service.ProductSearchService;
import org.apache.lucene.queryparser.xml.QueryBuilderFactory;
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;

import org.mybatis.logging.Logger;
import org.mybatis.logging.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;

/**
 * @className: ProductSearchServiceImpl
 * @Description: TODO
 * @version: v1.８.0
 * @author: 刘洋朔
 * @date: 2025/8/7 22:29
 */
@Service
public class ProductSearchServiceImpl implements ProductSearchService {
    private final static Logger log =
            LoggerFactory.getLogger(ProductSearchService.class);
    @Autowired
    private RestHighLevelClient client;

    /**
     * Es查询商品信息
     * @param params
     * @return
     */
    @Override
    public TableDataInfo search(SearchRequestParams params) throws IOException {
        try {
            //准备Request
            //创建一个Elasticsearch搜索请求,命名为"product
            SearchRequest request = new SearchRequest("product");
            // 2.准备DSL
            // 2.1.创建一个布尔查询构建器，用于组合多个查询条件
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
            //关键词搜索(all字段)
            //如果参数中有搜索关键字(key)，则添加一个must条件的match查询
            //在"all"字段上进行全文匹配搜索,"all"是商品多个字段的组合字段
            //"all" 通常是一个组合字段(copy_to字段)，包含多个其他字段的值(如商品名称、描述、品牌等)
            if(StringUtils.isNotEmpty(params.getKey())){
                boolQuery.must(QueryBuilders.matchQuery("all",params.getKey()));
            }
            // 精确匹配商品名称
            if(StringUtils.isNotEmpty(params.getName())){
                boolQuery.must(QueryBuilders.termQuery("name",params.getName()));
            }
            // 精确匹配品牌
            if(StringUtils.isNotEmpty(params.getBrand())){
                boolQuery.must(QueryBuilders.termQuery("brandName",params.getBrand()));
            }
            // 精确匹配状态
            if(StringUtils.isNotEmpty(params.getStatus())){
                boolQuery.must(QueryBuilders.termQuery("status",params.getStatus()));
            }
            // 如果没有查询条件，则查询所有
            if(!boolQuery.hasClauses()){
                //must表示将匹配所有文档的查询作为必须条件添加到布尔查询中
                boolQuery.must(QueryBuilders.matchAllQuery());
            }
            //将我们精心构建的布尔查询条件(boolQuery)设置到搜索请求(request)的查询主体中。
            request.source().query(boolQuery);
            // 2.2.分页
            int page = params.getPage() == null ? 1 : params.getPage();
            int size = params.getSize() == null ? 10 : params.getSize();
            //第一个是起始下标
            //第二个是展示条数
            request.source().from((page-1)*size).size(size);
            // 3.发送请求
            //负责将构建好的查询请求发送到 Elasticsearch 集群并获取结果。
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            //解析相应
            return handleResponse(response);
        } catch (IOException e) {
            throw new RuntimeException("商品搜索异常",e);
        }
    }

    /**
     * 同步所有数据
     * @param productDocs
     */
    @Override
    public void saveAll(ArrayList<ProductDoc> productDocs) throws IOException {
        try {
            //Elasticsearch的 批量添加请求
            BulkRequest request = new BulkRequest();
            // 2. 构建批量请求
            for (ProductDoc productDoc : productDocs) {
                String json = JSON.toJSONStringWithDateFormat(productDoc, "yyyy-MM-dd HH:mm:ss");
                request.add(new IndexRequest("product")
                        .id(productDoc.getId())
                        .source(json, XContentType.JSON));
            }
            //执行请求并获取响应
            BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
            //强制刷新索引,就和刷新页面一样,直接课件
            RefreshRequest refreshRequest = new RefreshRequest("product");
            //indices其实是index的复数形式
            client.indices().refresh(refreshRequest,RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //解析相应
    private TableDataInfo handleResponse(SearchResponse response) {
        SearchHits searchHits = response.getHits();
        //获取总条数
        long total = searchHits.getTotalHits().value;
        //文档数组
        SearchHit[] hits = searchHits.getHits();
        //创建productDoc集合
        ArrayList<ProductDoc> productDocs = new ArrayList<>(hits.length);
        //遍历结果
        for (SearchHit hit : hits) {
            //获取数据对象
            String json = hit.getSourceAsString();
            // 反序列化
            ProductDoc productDoc = JSON.parseObject(json, ProductDoc.class);
            productDocs.add(productDoc);
        }
        //封装返回
        return new TableDataInfo(productDocs,total);
    }

}
